package modele;

import java.awt.image.BufferedImage;

import java.util.Observable;
import java.util.Random;

import memory.NombreImpairException;

public class MGrid extends Observable {
	
	/*
	 * Modele d'une grille de jeu, caracterise :
	 * -L'ensemble des cartes de la partie
	 * -L'etat de la partie (gagnée ou en cours)
	 * -Leve une exception NombreImpairException à la construction si celle ci ne permet pas de donner un grille valide
	 * 
	 */
	
	protected boolean end;
	protected int height, width;
	protected MCard[][] grille;
	protected MTheme theme;
	protected MCard firstSelected = null;
	
	public MGrid(int h, int l, int th) throws NombreImpairException {
		if((h*l)%2 != 0) throw new NombreImpairException();
		
		end = false;
		height = h;
		width = l;
		
		grille = new MCard[height][width];
		theme = new MTheme(th);
		generateGame(theme);
	}
	
	/*
	 * Getters & Setters
	 */
	
	public MCard getCarte(int x, int y) {
		return grille[x][y];
	}
	
	protected boolean isEnd()
	{
		return end;
	}

	protected void setEnd(boolean end)
	{
		this.end = end;
		refresh();
	}

	public int getHeight() {
		return height;
	}
	
	public int getWidth() {
		return width;
	}
	
	public void setFirstSelected(MCard firstSelected)
	{
		this.firstSelected = firstSelected;
	}

	public MCard getFirstSelected() {
		return firstSelected;
	}

	public boolean hasFirstSelected() {
		return firstSelected != null;
	}
	
	//Verrouille toutes les cartes de la grille
	public void lockAll(boolean locked) {
		for(int i=0; i<getHeight(); i++)
			for(int j=0; j<getWidth(); j++)
				getCarte(i, j).setLocked(locked);
	}
	
	//Retourne toutes les cartes
	public void switchShowedAll() {
		for(int i=0; i<getHeight(); i++)
			for(int j=0; j<getWidth(); j++) {
				getCarte(i, j).switchShowed();
				getCarte(i, j).refresh();
			}
	}
	
	/*
	 * Algo de generation de grille
	 */
	
	//Methode principale
	protected void generateGame(MTheme th) {
        int[] coord;
        BufferedImage img;
        while(!isFull()) {
            img = th.getNewImage();
            coord = getEmptyCard();
            grille[coord[0]][coord[1]] = new MCard(this, img);
            coord = getEmptyCard();
            grille[coord[0]][coord[1]] = new MCard(this, img);
        }
	}

	
	protected int[] getEmptyCard() {
		/*
		 * Renvoi les coordonnées d'une carte carte null
		 */
        Random gen = new Random();
        int i = gen.nextInt(getHeight());
        int j = gen.nextInt(getWidth());
        while(getCarte(i, j) != null) {
            i = gen.nextInt(getHeight());
            j = gen.nextInt(getWidth());
        }
        int[] res = {i, j};
        return res;
	}

	protected boolean isFull() {
		/*
		 * Renvoi vrai ssi toutes les cartes de la grille sont construites
		 */
		boolean isFull = true;
        int i=0, j=0;
        while(isFull && i<getHeight()) {
            while(isFull && j<getWidth()) {
                isFull = grille[i][j] != null;
                j++;
            }
            i++;
            j=0;
        }
        return isFull;
	}
	
	public void update() {
		end = isAllNonVisible();
		if(end)
			refresh();
	}
	
	public void refresh() {
		setChanged();
		notifyObservers(null);
	}
	
	public boolean isAllNonVisible() {
		boolean all = true;
        int i=0, j=0;
        while(all && i<getHeight()) {
            while(all && j<getWidth()) {
                all = !grille[i][j].isVisible();
                j++;
            }
            i++;
            j=0;
        }
        return all;
	}
}
